package com.freewater.cargotracker.domain.model.cargo;

import com.freewater.cargotracker.domain.common.Value;
import com.freewater.cargotracker.domain.model.location.Location;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * Route specification. Describes where a cargo origin and destination is, and
 * the arrival deadline.
 */
public class RouteSpecification implements Serializable, Value {

    private static final long serialVersionUID = 1L;

    private final Location origin;
    private final Location destination;
    private final LocalDateTime arrivalDeadline;

    /**
     * @param origin          origin location - can't be the same as the destination
     * @param destination     destination location - can't be the same as the origin
     * @param arrivalDeadline arrival deadline
     */
    public RouteSpecification(Location origin, Location destination, LocalDateTime arrivalDeadline) {
        Validate.notNull(origin, "Origin is required");
        Validate.notNull(destination, "Destination is required");
        Validate.notNull(arrivalDeadline, "Arrival deadline is required");
        Validate.isTrue(!origin.sameValueAs(destination), "Origin and destination can't be the same: " + origin);

        this.origin = origin;
        this.destination = destination;
        this.arrivalDeadline = arrivalDeadline;
    }

    public Location getOrigin() {
        return origin;
    }

    public Location getDestination() {
        return destination;
    }

    public LocalDateTime getArrivalDeadline() {
        return arrivalDeadline;
    }

    private boolean saveValueAs(RouteSpecification other) {
        return other != null &&
                new EqualsBuilder()
                        .append(this.origin, other.origin)
                        .append(this.destination, other.destination)
                        .append(this.arrivalDeadline, other.arrivalDeadline)
                        .isEquals();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        final RouteSpecification other = (RouteSpecification) obj;
        return this.saveValueAs(other);
    }

    @Override
    public int hashCode() {
        return Objects.hash(origin, destination, arrivalDeadline);
    }
}
